const dgram = require('node:dgram')
const os = require('node:os')
const { ipcMain } = require('electron')

class UDPService {
  constructor(port = 51223) {
    this.socket = dgram.createSocket('udp4')
    this.port = port
    this.broadcastAddress = '' // 全网络广播
    this.mainWindow = null
    this.onlineUserList = []
    this.localIPs = [] // 本机局域网ip列表
    this.user = {
      userName: 'administrator', // 默认用户名
      address: '' // ip地址
    }
  }

  init(mainWindow) {
    this.mainWindow = mainWindow

    this.localIPs = this.getLocalIPs()

    // 接收消息处理
    this.socket.on('message', (msg, rinfo) => {
      const message = msg.toString()
      console.log(`Received from ${rinfo.address}:${rinfo.port}: ${message}`)
      const addressList = this.localIPs.map(item => item.ip)
      if (!addressList.includes(rinfo.address)) {
        // 来自非本机的消息
        try {
          const messageObj = JSON.parse(message)
          if (messageObj.status === 'login') {
            console.info('login')
            // 上线通知
            this.onlineUserList.push(messageObj)
            // 通知渲染进程xx上线
            this.mainWindow?.webContents.send('login-message', {
              ...messageObj,
              timestamp: new Date().toISOString()
            })
            // 发送上线消息到对方，告知对方自己在线
            // TODO 需要判断当前对方是否在自己在线列表，在就不需要通知对方
            const onlineIndex = this.onlineUserList.findIndex(
              user => user.address === rinfo.address
            )
            if (onlineIndex === -1) {
              // 当前消息发送人不在我的在线列表
              this.sendLogin()
            }
          } else if (messageObj.status === 'layout') {
            console.info('layout')
            // 下线通知
            const index = this.onlineUserList.findIndex(item => item.address === messageObj.address)
            if (index !== 0) {
              this.onlineUserList.splice(index, 1)
            }
          } else {
            console.info('mess', message)
            this.mainWindow?.webContents.send('udp-message', {
              message,
              from: {
                ip: rinfo.address,
                port: rinfo.port
              },
              timestamp: new Date().toISOString()
            })
          }
        } catch (error) {
          console.error(error)
          // 聊天消息
          // 转发到渲染进程
          this.mainWindow?.webContents.send('udp-message', {
            message,
            from: {
              ip: rinfo.address,
              port: rinfo.port
            },
            timestamp: new Date().toISOString()
          })
        }
      }
    })

    // 错误处理
    this.socket.on('error', err => {
      console.error(`UDP error:\n${err.stack}`)
      this.socket.close()
    })

    // 绑定端口
    this.socket.bind(this.port, '0.0.0.0', () => {
      console.log(`UDP server listening on port ${this.port}`)
      this.socket.setBroadcast(true)
    })

    // 注册IPC通信
    ipcMain.handle('send-udp-message', (event, { message, address, port = 51223 }) => {
      this.sendMessage(message, address, port)
    })

    ipcMain.handle('send-broadcast', (event, message) => {
      this.sendBroadcast(message)
    })

    // 上线通知
    this.sendLogin()
  }

  // 获取本机局域网IP列表
  getLocalIPs() {
    const interfaces = os.networkInterfaces()
    const localIPs = []

    Object.keys(interfaces).forEach(ifaceName => {
      interfaces[ifaceName].forEach(iface => {
        // 跳过非IPv4、回环地址和非活跃接口
        if (iface.family !== 'IPv4' || iface.internal || iface.address === '127.0.0.1') return
        // 检查是否为私有IP
        if (this.isPrivateIP(iface.address)) {
          const addrParts = iface.address.split('.').map(Number)
          const maskParts = iface.netmask.split('.').map(Number)
          // 计算广播地址：IP OR (NOT Netmask)
          const broadcast = addrParts.map((part, i) => part | (~maskParts[i] & 0xff))

          localIPs.push({
            interface: ifaceName,
            ip: iface.address,
            netmask: iface.netmask,
            broadcast: broadcast.join('.')
          })
        }
      })
    })

    return localIPs
  }

  // 检查IP是否在局域网私有范围内
  isPrivateIP(ip) {
    const parts = ip.split('.').map(Number)
    // 10.0.0.0/8
    if (parts[0] === 10) return true
    // 172.16.0.0/12
    if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true
    // 192.168.0.0/16
    if (parts[0] === 192 && parts[1] === 168) return true
    return false
  }

  // 发送定向消息
  sendMessage(message, address, port) {
    console.info(11, message, address, port)
    this.socket.send(message, port, address, err => {
      if (err) {
        console.error('Send message error:', err)
        this.mainWindow?.webContents.send('udp-error', err.message)
      }
    })
  }

  // 发送广播消息
  sendBroadcast(message) {
    this.socket.send(message, this.port, this.broadcastAddress, err => {
      if (err) {
        console.error('Broadcast error:', err)
        this.mainWindow?.webContents.send('udp-error', err.message)
      }
    })
  }

  // 上线广播
  sendLogin() {
    const message = {
      ...this.user,
      status: 'login'
    }
    this.localIPs.forEach(item => {
      message.address = item.ip
      this.socket.send(JSON.stringify(message), this.port, item.broadcast)
    })
  }

  // 下线广播
  sendLayout() {
    const message = {
      ...this.user,
      status: 'layout'
    }
    this.localIPs.forEach(item => {
      this.socket.send(JSON.stringify(message), this.port, item.broadcast)
    })
  }

  close() {
    this.sendLayout()
    this.socket.close()
  }
}

const udpService = new UDPService()
export default udpService
